package com.augurit.common.syslog.tool;

import java.sql.Timestamp;
import java.util.Date;

import org.hibernate.Session;
import org.hibernate.event.PostUpdateEvent;
import org.hibernate.event.PostUpdateEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springside.modules.web.struts2.Struts2Utils;

import com.augurit.common.entity.SysPropAuditLog;
import com.augurit.common.system.util.WebContextUtils;
import com.augurit.common.system.web.auth.form.LoginUserForm;
import com.augurit.common.util.lang.DateUtils;

/**
 * 字段审计日志
 * 注意：使用Hibernate事件机制，因此不能使用jdbc来生成字段审计日志。
 * 另外，对于同时保存多个entity时，DAO类在每次执行save方法后要紧接着调用flush方法，以便通知监听器监听每个entity的变更。
 */
@SuppressWarnings("serial")
public class AuditListener implements PostUpdateEventListener {

	private static Logger logger = LoggerFactory.getLogger(AuditListener.class);

	/**
	 * 当更新entity时触发
	 */
	public void onPostUpdate(PostUpdateEvent event) {
		Object entity = event.getEntity();

		if(entity instanceof IPropertyComment && event.getState() != null && event.getState().length > 0){
			
			for (int i=0; i<event.getState().length; i++) {
				
				String propertyName = event.getPersister().getPropertyNames()[i];
				Object oldValue = event.getOldState()[i];
				Object newValue = event.getState()[i];

				if(isModified(oldValue, newValue)){
					SysPropAuditLog log = new SysPropAuditLog();
					log.setEntity(entity.getClass().getSimpleName());
					log.setEntityId(event.getId().toString());
					log.setPropertyName(propertyName);
					log.setOldValue(formatToString(oldValue));
					log.setNewValue(formatToString(newValue));
					log.setUpdateTime(new Date());
					
					LoginUserForm loginUser = (LoginUserForm)Struts2Utils.getSession().getAttribute(WebContextUtils.SES_LOGIN_USER);
					log.setUpdator(loginUser.getUser().getUserName());

					log.setPropertyComment(((IPropertyComment)entity).buildPropertyComment().get(propertyName));
					
					savePropAuditLog(event.getSession(), log);
				}
			}
		}
	}
	
	/**
	 * 判断属性值是否被修改过
	 * @param oldValue
	 * @param newValue
	 * @return
	 */
	private boolean isModified(Object oldValue, Object newValue){	
		if (oldValue == null && newValue == null)
			return false;
		else if (oldValue != null && oldValue.toString() != "" && newValue == null)
			return true;
		else if (oldValue == null && newValue != null && newValue.toString() != "")
			return true;
		else if (oldValue instanceof Timestamp && newValue instanceof Date)
			return ((Date)newValue).compareTo((Timestamp)oldValue) != 0;
		else if (oldValue instanceof Date && newValue instanceof Timestamp)
			return ((Date)oldValue).compareTo((Timestamp)newValue) != 0;
		else if (oldValue.toString().equals(newValue.toString()))
			return false;
		else
			return true;
	}
	
	/**
	 * 格式化为字符串
	 * @param obj
	 * @return
	 */
	private String formatToString(Object obj){
		if(obj != null){
			if(obj instanceof Date){
				return DateUtils.dateTimeToString((Date)obj);
			}else{
				return obj.toString();
			}
		}
		return null;
	}
	
	/**
	 * 新增字段审计日志记录
	 * @param session
	 * @param log
	 */
	private void savePropAuditLog(Session session, SysPropAuditLog log) {
        session.clear();
        session.save(log);
        session.flush();
    }
}
